﻿using System;
using System.Collections.Generic;
using Mozi.HttpEmbedded.Extension;

namespace Mozi.Live.RTP
{
    /// <summary>
    /// RTCP数据报文抽象类
    /// </summary>
    public abstract class AbsRTCPPackage
    {
        /// <summary>
        /// 版本 2bits
        /// </summary>
        public byte Version { get; set; }
        /// <summary>
        /// 是否填充对齐 1bit
        /// </summary>
        public bool Padding { get; set; }
        /// <summary>
        /// 荷载的报文数 5bits
        /// </summary>
        public byte ReportCount { get; set; }
        /// <summary>
        /// 包类型 8bits 
        /// </summary>
        public abstract RTCPPackageType PackageType { get; set; }
        /// <summary>
        /// 长度字段16bits
        /// </summary>
        /// <remarks>整包长度/4-1 为4字节的倍数-1。这个值是后算出来的，构造类时不需要赋值</remarks>
        public ushort Length { get; set; }
        /// <summary>
        /// 打包成字节流
        /// </summary>
        /// <returns></returns>
        public abstract byte[] Pack();
        /// <summary>
        /// 公共构造函数
        /// </summary>
        public AbsRTCPPackage()
        {
            Version = 2;
        }
        /// <summary>
        /// 解析包的包头属性，几种类型的数据包都可用这个方法进行头属性通解。
        /// </summary>
        /// <param name="data">仅头部4个字节</param>
        /// <remarks>基本属性包括：Version,Padding,ReportCount,PackageType,Length</remarks>
        public void ParseHeader(byte[] data)
        {
            byte head = data[0];
            Version = (byte)(head >> 6);
            Padding = ((head & 0x20) >> 5) == 1;
            ReportCount = ((byte)(head & 0b00011111));
            PackageType = RTCPPackageType.Get<RTCPPackageType>(data[1].ToString());
            Length = (ushort)((data.GetBigEndianUInt16(2)+1)*4);
        }
        /// <summary>
        /// 打包包头属性
        /// </summary>
        /// <returns></returns>
        /// <remarks>基本属性包括：Version,Padding,ReportCount,PackageType,Length。需要注意的Length字段需要打包后重新测算，赋值到字节流在。</remarks>
        public byte[] PackHeader()
        {
            List<byte> bytes = new List<byte>();
            byte head = 0x00;
            head = (byte)(head | (byte)(Version << 6));
            head = (byte)(head | (Padding ? 0x00100000 : 0x00));

            ReportCount = (byte)(ReportCount & 0b00011111);
            head= (byte)(head |ReportCount);
            bytes.Add(head);
            bytes.Add(PackageType.Value);
            bytes.AddRange(Length.ToBigEndian());

            return bytes.ToArray();
        }
        /// <summary>
        /// 解析不同类型的数据报文
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static AbsRTCPPackage Parse(byte[] data)
        {
            RTCPPackageType pkType = RTCPPackageType.Get<RTCPPackageType>(data[1].ToString());

            AbsRTCPPackage pack = null;
            if (pkType == RTCPPackageType.ReceiverReport)
            {
                pack = RTCPReceiverPackage.Parse(data);
            }
            else if (pkType == RTCPPackageType.SenderReport)
            {
                pack = RTCPSenderPackage.Parse(data);
            }
            else if (pkType == RTCPPackageType.SourceDescription)
            {
                pack = RTCPSourceDescriptionPackage.Parse(data);
            }
            else if (pkType == RTCPPackageType.APP)
            {
                pack = RTCPAppPackage.Parse(data);
            }
            else if (pkType == RTCPPackageType.Goodbye)
            {
                pack = RTCPGoodbyePackage.Parse(data);
            }
            return pack;
        }
        //TODO 此处需要充分测试
        internal static AbsRTCPPackage[] ParsePackages(byte[] data,ref int offset2)
        {
            //最终的检索位置
            offset2 = 0;
            List<AbsRTCPPackage> packs = new List<AbsRTCPPackage>();
            int length = data.Length;
            while (offset2 < length)
            {
                byte[] buffer2 = new byte[length - offset2];
                Array.Copy(data, offset2, buffer2, 0, buffer2.Length);
                //TODO 
                AbsRTCPPackage pack = AbsRTCPPackage.Parse(buffer2);
                //响应RTP数据
                packs.Add(pack);
                if (pack != null)
                {
                    offset2 += pack.Length;
                }
                else
                {
                    offset2 += buffer2.Length;
                }
            }
            return packs.ToArray();
        }
    }
}
